package com.sinevil.tcpTrans.entity.json.handlers;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.sinevil.tcpTrans.entity.TCPJson;
import com.sinevil.tcpTrans.entity.json.BasicJson;
import com.sinevil.tcpTrans.entity.json.FilePacketJson;
import com.sinevil.tcpTrans.entity.json.InstructionJson;
import com.sinevil.tcpTrans.utils.BackEvent;
import com.sinevil.tcpTrans.utils.ReflectionUtils;
import com.sinevil.tcpTrans.utils.fileTrans.FileTranser;
import com.sinevil.tcpTrans.utils.log.FileTransLogger;
import com.sinevil.tcpTrans.utils.log.SocketJsonHandleLogger;

import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.BiConsumer;
import java.util.regex.Matcher;
import java.util.stream.Collectors;

/**
 * @Classname SocketJsonHandle
 * @Description TODO
 * @Version 1.0.0
 * @Date 2024/12/12 21:48
 * @Created by sinevil
 */
public abstract class SocketJsonHandle {


    protected int BUFFER_SIZE;

    /**
     * TCP数据包缓冲区
     */
    ByteBuffer readBuffer;
    ByteBuffer writeBuffer;

    /**
     * Json解析工具
     */
    public static final ObjectMapper objectMapper;

    /**
     * 用于文件传输的工具类
     */
    protected FileTranser fileTranser;

    /**
     * tcp数据包待处理缓冲区
     */
    protected LinkedBlockingQueue<TCPJson> tcpJsons = new LinkedBlockingQueue<>();
    // 用于 添加和处理TCP数据包的锁
    private final ReentrantLock TcpJsonsLock = new ReentrantLock();
    // 定义Condition用于控制handlerThread线程等待和唤醒，
    private final Condition ProgressTcpJsonsCondition = TcpJsonsLock.newCondition();
    /**
     * 用于处理TCP数据包的线程
     */
    protected final Thread handlerThread;

    /**
     * 用于Json数据类和对应的处理函数的Map
     */
    protected Map<Class<? extends BasicJson>, BiConsumer<BasicJson, SocketChannel>> jsonMessageHandlersMap = new HashMap<>();

    /**
     * 用于存储指令码和对应的处理函数的Map
     */
    protected Map<Integer, BiConsumer<InstructionJson, SocketChannel>> instructionHandlersMap;

    /**
     * 用于存储文件包对象和对应的处理函数的Map
     */
    protected Map<Class<? extends FilePacketJson>, BiConsumer<FilePacketJson, SocketChannel>> filePacketHandlersMap;

    static {
        objectMapper = new ObjectMapper();
    }



    protected SocketJsonHandle() {
        this.handlerThread = new HandlerThread();
        handlerThread.start();
    }

    public static boolean isValidFilePath(String location) {
        Path path = Paths.get(location);
        // 检查路径是否为绝对路径
        if (!path.isAbsolute()) {
            return false;
        }
        // 检查路径是否指向一个存在的文件
        return Files.exists(path) && Files.isRegularFile(path);
    }

    /**
     * 初始化默认的指令Json数据类对象和处理函数的映射关系
     */
    protected void initInstructionHandlersMap() {
        this.instructionHandlersMap = new HashMap<>();
        this.jsonMessageHandlersMap.put(InstructionJson.class, this::handleInstruction);

    }

    protected void initFilePacketHandlersMap(){
        this.filePacketHandlersMap = new HashMap<>();
        this.jsonMessageHandlersMap.put(FilePacketJson.class, this::handleFilePacketJson);
    }

    public void addToJsonHandlersMap(Class<? extends BasicJson> basicJson, BiConsumer<BasicJson, SocketChannel> handle){
        this.jsonMessageHandlersMap.put(basicJson,handle);
    }

    public void addToInstructionHandlersMap(Integer code, BiConsumer<InstructionJson, SocketChannel> handle){
        this.instructionHandlersMap.put(code, handle);
    }

    public void addToFilePacketHandlersMap(Class<? extends FilePacketJson>  filePacketJson,BiConsumer<FilePacketJson, SocketChannel> handle){
        this.filePacketHandlersMap.put(filePacketJson, handle);
    }

    public void close() {
        // 清理ByteBuffer，将其标记为可回收状态
        readBuffer.clear();
        writeBuffer.clear();
        this.handlerThread.interrupt();
    }

    /**
     * 用于处理连接的核心方法
     */
    public void handle(SocketChannel socketChannel, BasicJson basicJson) {
        TcpJsonsLock.lock();
        try{
            // 将待处理的TCP数据包添加到队列中，并唤醒处理线程进行处理
            this.tcpJsons.offer(new TCPJson(socketChannel,basicJson));
            this.ProgressTcpJsonsCondition.signal();
        }finally {
            TcpJsonsLock.unlock();
        }
    };

    /**
     * 处理 指令类型数据
     * @param basicJson 指令数据包
     * @param socketChannel 服务端套接字
     */
    private void handleInstruction(BasicJson basicJson,SocketChannel socketChannel){
        InstructionJson instructionJson = (InstructionJson) basicJson;
        final Map.Entry<Object,Method> om = CallbackRegistryManager.getCallback(instructionJson.getCode());
        if (om != null){
            try {
                Method method = om.getValue();
//                System.out.println("回调函数被执行:"+method.getName() +"  instructionJson:"+instructionJson);
                method.invoke(om.getKey(),socketChannel, instructionJson);
            } catch (Exception e) {
                SocketJsonHandleLogger.LOGGER.error("回调异常,instructionCode:{}", instructionJson.getCode(), e);
                throw new RuntimeException(e);
            }
        }
        BiConsumer<InstructionJson, SocketChannel> handler = this.instructionHandlersMap.get(instructionJson.getCode());
        if (handler != null){
            handler.accept(instructionJson,socketChannel);
        }
    }

    /**
     * 处理 文件数据包类型数据
     * @param basicJson 文件数据包
     * @param socketChannel 服务端套接字
     */
    private void handleFilePacketJson(BasicJson basicJson,SocketChannel socketChannel){
        FilePacketJson filePacketJson = (FilePacketJson) basicJson;
        BiConsumer<FilePacketJson, SocketChannel> handler = this.filePacketHandlersMap.get(filePacketJson.getClass());
        if (handler != null){
            handler.accept(filePacketJson,socketChannel);
        }
    }


    class HandlerThread extends Thread{
        @Override
        public void run() {
            BasicJson basicJson;
            TCPJson tcpJson;
            while (!isInterrupted()) {
                TcpJsonsLock.lock();
                try {
                    if (tcpJsons.isEmpty())
                        ProgressTcpJsonsCondition.await();
                } catch (InterruptedException e) {
                    interrupt();
                    throw new RuntimeException(e);
                }
                finally {
                    TcpJsonsLock.unlock();
                }
                while (!tcpJsons.isEmpty()){
                    tcpJson = tcpJsons.poll();
                    basicJson = tcpJson.getBasicJson();
//                    System.out.println(basicJson.toString());
                    jsonMessageHandlersMap.get(basicJson.getClass()).accept(basicJson, tcpJson.getSocketChannel());
                }

            }
            interrupt();
        }
    }

    // 一些公共的处理方法

    protected void handlePUBLIC_ACCEPT_FILE_PACKET(FilePacketJson filePacketJson, SocketChannel socketChannel){
        this.fileTranser.acceptFilePacket(socketChannel,filePacketJson);
    }

    /**
     * 接收上传端返回的文件MD5
     * @param instructionJson 上传端返回的文件MD5
     * @param socketChannel 上传端套接字
     */
    protected void handlePUBLIC_FILE_MD5(InstructionJson instructionJson, SocketChannel socketChannel){
        String content = instructionJson.getContent();
        Matcher matcher = InstructionJson.PUBLIC_FILE_MD5_PATTERN.matcher(content);
        if (matcher.find()) {
            String uid = matcher.group(1);
            String md5 = matcher.group(2);
            this.fileTranser.acceptUploadMD5(socketChannel, uid, md5);
        }
    }

    /**
     * 请求下载文件时，上传端发送错误
     * @param instructionJson 服务端返回的失败任务信息
     * @param socketChannel 套接字
     */
    public void handlePUBLIC_UPLOAD_ERROR_REQUEST_FILE(InstructionJson instructionJson, SocketChannel socketChannel){
        String content = instructionJson.getContent();
        Matcher matcher = InstructionJson.PUBLIC_UPLOAD_ERROR_REQUEST_FILE_PATTERN.matcher(content);
        if (matcher.find()) {
            String filePath = matcher.group(1);
            String cont = matcher.group(2);
            fileTranser.cancelDownload(socketChannel,filePath);
            FileTransLogger.LOGGER.warn("{}:{}", cont, filePath);
        }
    }

    /**
     * 设置回调函数的对象
     * @param objects 对象
     */
    public void setObjectForBackEvent(Object... objects){
        CallbackRegistryManager.registerCallbacks(objects);
    }


    /**
     * 回调注册管理器
     */
    private static class CallbackRegistryManager {
        protected static final Map<Integer, Map.Entry<Object,Method>> callbackMap = new HashMap<>();

        /**
         * 注册回调函数的对象
         * @param objects 回调函数的类对象
         */
        public static void registerCallbacks(Object... objects){
            if (objects == null || objects.length == 0)
                return;

            // 构建类与对象的映射
            Map<Class<?>, Object> coMap = java.util.Arrays.stream(objects)
                    .collect(Collectors.toMap(Object::getClass, obj -> obj));


            // 获取被 @BackEvent 注解的所有方法
            List<Method> annotatedMethods = ReflectionUtils.scanMethodsWithAnnotation(BackEvent.class);

            // 处理带有 @BackEvent 注解的方法
            annotatedMethods.stream()
                    .filter(method -> method.getAnnotation(BackEvent.class) != null)
                    .filter(CallbackRegistryManager::isValidMethod)
                    .forEach(method -> {
                        BackEvent backEvent = method.getAnnotation(BackEvent.class);
                        Class<?> cls = method.getDeclaringClass();
                        Object targetObject = coMap.get(cls);
                        if (targetObject != null) {
                            int instructionCode = backEvent.instructionCode();
                            callbackMap.put(instructionCode, Map.entry(targetObject, method));
                        } else {
                            SocketJsonHandleLogger.LOGGER.warn("未找到方法 {} 所在类的对象实例", method.getName());
                        }
                    });
        }

        /**
         * 验证方法的参数是否符合要求
         * @param method 要验证的方法
         * @return 如果参数符合要求返回 true，否则返回 false
         */
        private static boolean isValidMethod(Method method) {
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length == 2) {
                Class<?> parameterType1 = parameterTypes[0];
                if (parameterType1 != SocketChannel.class) {
                    SocketJsonHandleLogger.LOGGER.error("方法 {} 被 @BackEvent 注解，第一个参数必须为 SocketChannel.", method.getName());
                    return false;
                }
                Class<?> parameterType2 = parameterTypes[1];
                if (parameterType2 != InstructionJson.class) {
                    SocketJsonHandleLogger.LOGGER.error("方法 {} 被 @BackEvent 注解，第二个参数必须为 InstructionJson.", method.getName());
                    return false;
                }
                return true;

            }
            return false;
        }


        /**
         * 根据指令码获取对应的回调函数
         * @param instructionCode 指令码
         * @return （类对象，回调函数）
         */
        public static Map.Entry<Object, Method> getCallback(int instructionCode) {
            return callbackMap.get(instructionCode);
        }

    }


}